import { groupBy, isEqual } from 'lodash';
import pageTabUtil from '@/utils/pageTabUtil';
import { useEffect, useRef } from 'react';
// eslint-disable-next-line import/no-unresolved
// import history from '@@/history';
import { history } from 'umi'

const MESSAGE_TYPE = {
    REFRESH: 'refresh'
};

const messageList = [];
const toFromTabMap = {};

const getCurrentLocation = () => history.location;
const getHref = (pathname, query = {}) => pageTabUtil.generateKey({ pathname, query });
const getCurrenHref = () => pageTabUtil.generateKey(history.location);
const convertSearchToObject = search =>
    search ? JSON.parse(`{${search.replace(/\??(\w+)=([^&]+)(&?)/g, '"$1":"$2",').replace(/,$/, '')}}`) : null;

const getSearch = path => /\?[^#]+/.exec(path)?.[0];
const getPathname = path => String(path).substring(0, path.indexOf('?') >= 0 ? path.indexOf('?') : path.length);

const isEqualPath = (path1, path2) => {
    if (path1 === path2) {
        return true;
    }
    const pathName1 = getPathname(path1);
    const pathName2 = getPathname(path2);

    if (pathName1 !== pathName2) {
        return false;
    }

    const search1 = convertSearchToObject(getSearch(path1));
    const search2 = convertSearchToObject(getSearch(path2));
    return pathName1 === pathName2 && isEqual(search1, search2);
};

const tabMessageUtil = {
    /**
     * 是否已经存在页签中
     * @param to
     * @returns {boolean}
     */
    inTabs(to) {
        const { tabsState = [] } = pageTabUtil;
        return !!tabsState.find(state => isEqualPath(getHref(state.location.pathname, state.location?.query), to));
    },

    /**
     * 发送消息
     * @param to 接收消息页签编码
     * @param message 消息体
     * @param fromTabKey 发送消息的页签
     */
    push({ to, from, type, message }) {
        if (!tabMessageUtil.inTabs(to)) {
            return;
        }

        messageList.push({
            to,
            from,
            type,
            message
        });
    },

    /**
     * 接收消息
     * @param to 接收消息页签
     * @param type 接收消息的类型
     * @returns {*}
     */
    take(to, type) {
        const { take = [], leave = [] } = groupBy(messageList, messageInfo =>
            isEqualPath(messageInfo.to, to) && (type ? messageInfo.type === type : true) ? 'take' : 'leave'
        );
        // 删除原来所有的项，添加剩下的项
        messageList.splice(0, messageList.length, ...leave);
        return take;
    },

    /**
     * 在当前页签推送消息
     * @param to 要发送的页签
     * @param type 消息类型
     * @param message 消息体
     */
    pushByCurrentLocation({ to, type, message }) {
        tabMessageUtil.push({
            to,
            from: getCurrenHref(),
            type,
            message
        });
    },

    /**
     * 通知刷新
     * @param to 要刷新的页签
     */
    noticeRefresh(to) {
        tabMessageUtil.pushByCurrentLocation({
            to,
            type: MESSAGE_TYPE.REFRESH
        });
    },

    /**
     * 获取当前页签的消息
     * @param {?}type
     * @returns {Array}
     */
    takeByCurrentTab(type) {
        return tabMessageUtil.take(getCurrenHref(), type);
    },

    memoFromTo(
        toPathName,
        toQuery,
        fromPathname = getCurrentLocation().pathname,
        fromQuery = getCurrentLocation()?.query
    ) {
        toFromTabMap[getHref(toPathName, toQuery)] = getHref(fromPathname, fromQuery);
    },

    /**
     * 能过路由配置打开新的页签，并记住来源页签
     * @param routerConfig
     */
    openMemoTabByRouterConfig(routerConfig) {
        tabMessageUtil.memoFromTo(routerConfig.pathname, routerConfig.query);
        history.push(routerConfig);
    },

    /**
     * 通知来源页签（打开当前页签的页签）刷新
     */
    noticeFromRefresh() {
        const to = getCurrenHref();
        const from = toFromTabMap[to];
        if (!from) {
            console.warn(`没找到${to}的来源页签`);
            return;
        }
        // 向来源页签发送消息
        tabMessageUtil.pushByCurrentLocation({
            to: from,
            type: MESSAGE_TYPE.REFRESH
        });
    },

    /**
     * 通知与给定pathnameList页面刷新（只比较pathname, 不比较search(query)）
     * @param pathnameList
     */
    noticeRefreshByPathname(...pathnameList) {
        const { tabsState = [] } = pageTabUtil;
        pathnameList.forEach(pathname => {
            tabsState.forEach(tabItem => {
                if (pathname === tabItem.location.pathname) {
                    tabMessageUtil.pushByCurrentLocation({
                        to: getHref(tabItem.location.pathname, tabItem.location.query),
                        type: MESSAGE_TYPE.REFRESH
                    });
                }
            });
        });
    },

    equalPath(firstPathname, firstQuery, secondPathname, secondQuery) {
        return isEqualPath(getHref(firstPathname, firstQuery), getHref(secondPathname, secondQuery));
    }
};

/**
 * 处理刷新消息
 * @param refreshFn
 */
const useHandleRefreshMessage = refreshFn => {
    const executeRefreshFn = useRef(null);

    useEffect(() => {
        executeRefreshFn.current = refreshFn;
    }, [refreshFn]);

    useEffect(() => {
        const { pathname: pagePathname, query: pageQuery } = getCurrentLocation();

        return history.listen(({ pathname, query, state } /* , action */) => {
            const pageHref = getHref(pagePathname, pageQuery);
            const path = getHref(pathname, query);

            if (!isEqualPath(pageHref, path) || state?.tabRoute) {
                return;
            }

            // 取到当前信息
            const refreshMessageList = tabMessageUtil.take(path, MESSAGE_TYPE.REFRESH);

            // 没有当前信息时，直接返回
            if (!refreshMessageList || refreshMessageList.length === 0) {
                return;
            }

            if (executeRefreshFn.current) {
                // 要等待global.js中的history.listen先处理完页签问题再执行，不然可能会造成顶部菜单没有的问题
                setTimeout(() => {
                    executeRefreshFn.current();
                }, 10);
            } else {
                // 要等待global.js中的history.listen先处理完页签问题再执行，不然可能会造成顶部菜单没有的问题
                setTimeout(() => {
                    pageTabUtil.refreshTab();
                }, 10);
            }
        });
    }, []);
};

export default tabMessageUtil;
export { MESSAGE_TYPE, useHandleRefreshMessage };
